package com.onlyphoto.onlymall.utils

import android.Manifest
import android.app.Activity
import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.database.Cursor
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.graphics.Point
import android.location.LocationManager
import android.media.ExifInterface
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.telephony.TelephonyManager
import android.text.Editable
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextWatcher
import android.text.style.ForegroundColorSpan
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.View
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.TextView
import androidx.core.content.ContextCompat

import java.io.ByteArrayOutputStream

import java.io.File
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.lang.reflect.Field
import java.text.SimpleDateFormat

/**
 * Created by gaochujia on 2019-6-27.
 */

object AndroidUtils {

    /**************
     * 获取sdk路径
     *
     * @return
     */
    val sdCardPath: String
        get() = Environment.getExternalStorageDirectory().absolutePath

    //获取当前设备信息
    val deviceName: String
        get() {
            try {
                return Build.MODEL
            } catch (e: Exception) {
                e.printStackTrace()
                return ""
            }

        }

    //获取当前系统的版本号
    val osVersion: String
        get() {
            try {
                return Build.VERSION.RELEASE
            } catch (e: Exception) {
                e.printStackTrace()
                return ""
            }

        }

    private val mTmpValue = TypedValue()

    /**
     * 手机号码长度
     */
    val PHONE_LENGTH = 11
    /**
     * 验证码最小长度
     */
    val CODE_LENGTH = 6
    /**
     * 密码最小长度
     */
    val PWD_LENGTH = 6

    fun getScreenSize(context: Context): Point {
        val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        val display = windowManager.defaultDisplay
        val point = Point()
        if (Build.VERSION.SDK_INT >= 17) {
            display.getRealSize(point)
        } else {
            display.getSize(point)
        }
        return point
    }


    /**
     * 建立部分字符串不同颜色的字符串.
     *
     * @param text  源字符串
     * @param start 开始位置
     * @param end   结束位置
     * @param color 改变的颜色
     * @return SpannableStringBuilder对象，可以直接供给TextView
     */
    fun buildStringSpannable(
            text: CharSequence, start: Int, end: Int, color: Int): SpannableStringBuilder {
        val spannable = SpannableStringBuilder(text)// 用于可变字符串
        val span = ForegroundColorSpan(color)
        spannable.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
        return spannable
    }

    /**
     * 获取手机显示数据.
     *
     * @param activity 活动对象
     * @return 手机手机显示数据
     */
    fun getDisplayMetrics(activity: Activity?): DisplayMetrics {
        if (activity != null) {
            val metric = DisplayMetrics()
            activity.windowManager.defaultDisplay.getMetrics(metric)
            return metric
        } else {
            throw RuntimeException("Activity must not be null.")
        }
    }

    /*************
     * 获取屏幕宽跟高
     *
     * @param context
     * @return
     */
    fun getScreenExtent(context: Context): IntArray {
        val buf = IntArray(2)
        val metric = context.resources.displayMetrics
        val height = metric.heightPixels     // 屏幕高度（像素）
        val width = metric.widthPixels     // 屏幕宽度（像素）
        buf[0] = width
        buf[1] = height
        return buf
    }

    fun <T> getExtrasFromIntent(intent: Intent, key: String): T? {
        val extras = intent.extras
        if (extras != null) {
            if (extras.containsKey(key)) {
                try {
                    return extras.get(key) as T
                } catch (e: ClassCastException) {
                    e.printStackTrace()
                }

            }
        }
        return null
    }

    /**
     * 获取安装app的意图.
     *
     * @param apkFile
     * @return
     */
    fun getInstallIntent(apkFile: File): Intent {
        val intent = Intent()
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        intent.action = Intent.ACTION_VIEW
        val type = "application/vnd.android.package-archive"
        intent.setDataAndType(Uri.fromFile(apkFile), type)
        return intent
    }

    /**
     * 从TextView获取整型值，如果获取的数据不能转换成预期的数据，则反回默认值.
     *
     * @param textView     要取值的那个TextView组件
     * @param defaultValue 默认值
     * @return 返回整型值
     */
    fun getIntFromTextView(textView: TextView,
                           defaultValue: Int?): Int? {
        try {
            val trim = textView.text.toString().trim { it <= ' ' }
            return Integer.valueOf(trim)
        } catch (e: NumberFormatException) {
            return defaultValue
        }

    }

    /**
     * 判断网络是否可用.
     *
     * @param context 上下文
     * @return true代表网络可用，false代表网络不可用.
     */
    fun isNetworkValid(context: Context): Boolean {
        var result = false
        val connectivity = context
                .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        if (connectivity == null) {
            result = false
        } else {
            val info = connectivity.activeNetworkInfo
            if (info == null) {
                result = false
            } else {
                if (info.isAvailable) {
                    result = true
                }
            }
        }
        return result
    }

    fun isValidLocationNetwork(context: Context): Boolean {
        val locationManager = context
                .getSystemService(Context.LOCATION_SERVICE) as LocationManager
        return locationManager
                .isProviderEnabled(LocationManager.NETWORK_PROVIDER)
    }

    fun isValidLocation(context: Context): Boolean {
        return isValidLocationNetwork(context) || isValidLocationGps(context)
    }

    fun isValidLocationGps(context: Context): Boolean {
        val locationManager = context
                .getSystemService(Context.LOCATION_SERVICE) as LocationManager
        return locationManager
                .isProviderEnabled(LocationManager.GPS_PROVIDER)
    }

    fun isPhoneNetworkValid(context: Context, type: Int): Boolean {
        val conMan = context
                .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val mobile = conMan.getNetworkInfo(type)!!.state
        return mobile == NetworkInfo.State.CONNECTED || mobile == NetworkInfo.State.CONNECTING
    }

    /**
     * 安全执行runnable的UI事件.
     *
     * @param activity
     * @param runnable
     */
    fun runOnUiThreadSafety(activity: Activity?,
                            runnable: Runnable?) {
        if (activity == null) {
            return
        }
        if (runnable == null) {
            return
        }
        activity.runOnUiThread {
            try {
                runnable.run()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    /**
     * 隐藏当前界面存在的系统软键盘
     */
    fun hideSoftInput(activity: Activity) {
        if (activity.currentFocus != null) {
            val inputManger = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            inputManger.hideSoftInputFromWindow(activity.currentFocus?.windowToken, 0)
        }

    }

    //获取当前app的版本号
    fun getAppVersion(context: Context): String {
        try {
            val packageManager = context.packageManager
            val packInfo: PackageInfo
            packInfo = packageManager.getPackageInfo(context.packageName, 0)
            return packInfo.versionName
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
            return ""
        }

    }

    //获取当前设备ID
    fun getDeviceId(context: Context): String {
        try {
            val tm = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            return if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                ""
            } else tm.deviceId
        } catch (e: Exception) {
            e.printStackTrace()
            return ""
        }

    }

    //获取当前设备ID
    fun getInstalledTime(context: Context): String {
        var installedTime = ""
        val packageManager = context.packageManager
        try {
            val packageInfo = packageManager.getPackageInfo(context.packageName, 0)
            val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
            val firstInstallTime = packageInfo.firstInstallTime//应用第一次安装的时间
            installedTime = sdf.format(firstInstallTime)
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }

        return installedTime
    }

    fun saveImageToGallery(context: Context, bmp: Bitmap) {
        // 首先保存图片
        val appDir = File(Environment.getExternalStorageDirectory(), "dnStock")
        if (!appDir.exists()) {
            appDir.mkdir()
        }
        val fileName = System.currentTimeMillis().toString() + ".jpg"
        val file = File(appDir, fileName)
        try {
            val fos = FileOutputStream(file)
            bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos)
            fos.flush()
            fos.close()
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }

        // 其次把文件插入到系统图库
        try {
            MediaStore.Images.Media.insertImage(context.contentResolver,
                    file.absolutePath, fileName, null)
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        }

        // 最后通知图库更新
        context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file.absolutePath)))
    }

    fun getXmlDef(context: Context, id: Int): Int {
        synchronized(mTmpValue) {
            val value = mTmpValue
            context.resources.getValue(id, value, true)
            return TypedValue.complexToFloat(value.data).toInt()
        }
    }

    /**
     * 通过指定树龄的EditText的长度来控制任意view的enable状态
     * 主要用于登录注册页面的输入框判断
     * TODO 目前暂未实现对最大长度的控制
     *
     * @param minLengthAraay EditText对应的最小长度
     * @param enableView     需要控制的view
     * @param ets            对应的EditText
     */
    fun isButtonEnable(minLengthAraay: IntArray?, enableView: View, vararg ets: EditText) {
        if (minLengthAraay == null || ets == null) return //有空值，直接结束
        if (minLengthAraay.size != ets.size) return //数量不匹配，直接结束
        for (i in ets.indices) {
            if (ets == null || minLengthAraay[i] < 0) return //传入值非法，直接结束
        }

        val watcher = object : TextWatcher {
            override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {

            }

            override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
                var enable = true
                for (j in ets.indices) {
                    if (ets[j].text.length < minLengthAraay[j]) {//如果大于表示匹配成功
                        enable = false
                    }
                }
                enableView.isEnabled = enable
            }

            override fun afterTextChanged(editable: Editable) {

            }
        }

        //以此3设置监听器
        for (i in ets.indices) {
            ets[i].addTextChangedListener(watcher)
        }

    }

    /**
     * 得到状态栏的高度
     *
     * @param context 上下文
     * @return 状态栏的高度
     */
    fun getStatusBarHeight(context: Context): Int {
        var c: Class<*>? = null
        var obj: Any? = null
        var field: Field? = null
        var x = 0
        var sbar = 0
        try {
            c = Class.forName("com.android.internal.R\$dimen")
            obj = c!!.newInstance()
            field = c.getField("status_bar_height")
            x = Integer.parseInt(field!!.get(obj).toString())
            sbar = context.resources.getDimensionPixelSize(x)
        } catch (e1: Exception) {
            e1.printStackTrace()
        }

        return sbar
    }

    /**
     * 专为Android4.4设计的从Uri获取文件绝对路径，以前的方法已不好使
     */
    fun getPath(context: Context, uri: Uri): String? {

        // DocumentProvider
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                val docId = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                val type = split[0]

                if ("primary".equals(type, ignoreCase = true)) {
                    return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
                }

                // TODO handle non-primary volumes
            } else if (isDownloadsDocument(uri)) {

                val id = DocumentsContract.getDocumentId(uri)
                val contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))

                return getDataColumn(context, contentUri, null, null)
            } else if (isMediaDocument(uri)) {
                val docId = DocumentsContract.getDocumentId(uri)
                val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                val type = split[0]

                var contentUri: Uri? = null
                if ("image" == type) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                } else if ("video" == type) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                } else if ("audio" == type) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                }

                val selection = "_id=?"
                val selectionArgs = arrayOf(split[1])

                return getDataColumn(context, contentUri, selection, selectionArgs)
            }// MediaProvider
            // DownloadsProvider
        } else if ("content".equals(uri.scheme!!, ignoreCase = true)) {
            return getDataColumn(context, uri, null, null)
        } else if ("file".equals(uri.scheme!!, ignoreCase = true)) {
            return uri.path
        }// File
        // MediaStore (and general)

        return null
    }

    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context       The context.
     * @param uri           The Uri to query.
     * @param selection     (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    fun getDataColumn(context: Context, uri: Uri?, selection: String?,
                      selectionArgs: Array<String>?): String? {

        var cursor: Cursor? = null
        val column = "_data"
        val projection = arrayOf(column)

        try {
            cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null)
            if (cursor != null && cursor.moveToFirst()) {
                val column_index = cursor.getColumnIndexOrThrow(column)
                return cursor.getString(column_index)
            }
        } finally {
            cursor?.close()
        }
        return null
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    fun isExternalStorageDocument(uri: Uri): Boolean {
        return "com.android.externalstorage.documents" == uri.authority
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    fun isDownloadsDocument(uri: Uri): Boolean {
        return "com.android.providers.downloads.documents" == uri.authority
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    fun isMediaDocument(uri: Uri): Boolean {
        return "com.android.providers.media.documents" == uri.authority
    }

    /**
     * 读取图片的旋转的角度
     *
     * @param path 图片绝对路径
     * @return 图片的旋转角度
     */
    fun getBitmapDegree(path: String): Int {
        var degree = 0
        try {
            // 从指定路径下读取图片，并获取其EXIF信息
            val exifInterface = ExifInterface(path)
            // 获取图片的旋转信息
            val orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL)
            when (orientation) {
                ExifInterface.ORIENTATION_ROTATE_90 -> degree = 90
                ExifInterface.ORIENTATION_ROTATE_180 -> degree = 180
                ExifInterface.ORIENTATION_ROTATE_270 -> degree = 270
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }

        return degree
    }


    /***********
     * 获取图片压缩后的bitmap
     *
     * @param srcPath
     * @return
     */
    fun getCompressedBmp(srcPath: String): Bitmap {
        val newOpts = BitmapFactory.Options()
        //开始读入图片，此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true
        var bitmap = BitmapFactory.decodeFile(srcPath, newOpts)//此时返回bm为空

        newOpts.inJustDecodeBounds = false
        val w = newOpts.outWidth
        val h = newOpts.outHeight
        //现在主流手机比较多是800*480分辨率，所以高和宽我们设置为
        val hh = 853f//这里设置高度为800f
        val ww = 480f//这里设置宽度为480f
        //缩放比。由于是固定比例缩放，只用高或者宽其中一个数据进行计算即可
        var be = 1//be=1表示不缩放
        if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
            be = (newOpts.outWidth / ww).toInt()
        } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
            be = (newOpts.outHeight / hh).toInt()
        }
        if (be <= 0)
            be = 1
        newOpts.inSampleSize = be//设置缩放比例
        //重新读入图片，注意此时已经把options.inJustDecodeBounds 设回false了
        bitmap = BitmapFactory.decodeFile(srcPath, newOpts)
        return compressImage(bitmap)//压缩好比例大小后再进行质量压缩
    }

    private fun compressImage(image: Bitmap): Bitmap {
        var image = image
        //图片允许最大空间   单位：KB
        val maxSize = 100.00
        //将bitmap放至数组中，意在bitmap的大小（与实际读取的原文件要大）
        val baos = ByteArrayOutputStream()
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos)
        val b = baos.toByteArray()
        //将字节换成KB
        val mid = (b.size / 1024).toDouble()
        //判断bitmap占用空间是否大于允许最大空间  如果大于则压缩 小于则不压缩
        if (mid > maxSize) {
            //获取bitmap大小 是允许最大大小的多少倍
            val i = mid / maxSize
            //开始压缩  此处用到平方根 将宽带和高度压缩掉对应的平方根倍 （1.保持刻度和高度和原bitmap比率一致，压缩后也达到了最大大小占用空间的大小）
            image = zoomImage(image, image.width / Math.sqrt(i), image.height / Math.sqrt(i))
        }
        return image
    }

    fun zoomImage(bgimage: Bitmap, newWidth: Double,
                  newHeight: Double): Bitmap {
        // 获取这个图片的宽和高
        val width = bgimage.width.toFloat()
        val height = bgimage.height.toFloat()
        // 创建操作图片用的matrix对象
        val matrix = Matrix()
        // 计算宽高缩放率
        val scaleWidth = newWidth.toFloat() / width
        val scaleHeight = newHeight.toFloat() / height
        // 缩放图片动作
        matrix.postScale(scaleWidth, scaleHeight)
        return Bitmap.createBitmap(bgimage, 0, 0, width.toInt(),
                height.toInt(), matrix, true)
    }

    /**
     * 将图片按照某个角度进行旋转
     *
     * @param bm     需要旋转的图片
     * @param degree 旋转角度
     * @return 旋转后的图片
     */
    fun rotateBitmapByDegree(bm: Bitmap, degree: Int): Bitmap {
        var returnBm: Bitmap? = null

        // 根据旋转角度，生成旋转矩阵
        val matrix = Matrix()
        matrix.postRotate(degree.toFloat())
        try {
            // 将原始图片按照旋转矩阵进行旋转，并得到新的图片
            returnBm = Bitmap.createBitmap(bm, 0, 0, bm.width, bm.height, matrix, true)
        } catch (e: OutOfMemoryError) {
        }

        if (returnBm == null) {
            returnBm = bm
        }
        if (bm != returnBm) {
            bm.recycle()
        }
        return returnBm
    }

    /***********
     * 图片保存文件
     *
     * @param filePath
     * @param bitmap
     */
    fun saveBitmap(filePath: String, bitmap: Bitmap) {

        val f = File(filePath)
        if (f.exists()) {
            f.delete()
        }
        try {
            val out = FileOutputStream(f)
            bitmap.compress(Bitmap.CompressFormat.PNG, 90, out)
            out.flush()
            out.close()
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    /*********
     * 获取当前网络信息
     *
     * @return
     */
    fun getNetworkType(context: Context): String {
        var strNetworkType = ""

        val networkInfo = (context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager).activeNetworkInfo
        if (networkInfo != null && networkInfo.isConnected) {
            if (networkInfo.type == ConnectivityManager.TYPE_WIFI) {
                strNetworkType = "WIFI"
            } else if (networkInfo.type == ConnectivityManager.TYPE_MOBILE) {
                val _strSubTypeName = networkInfo.subtypeName

                // TD-SCDMA   networkType is 17
                val networkType = networkInfo.subtype
                when (networkType) {
                    TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_EDGE, TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyManager.NETWORK_TYPE_IDEN //api<8 : replace by 11
                    -> strNetworkType = "2G"
                    TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyManager.NETWORK_TYPE_HSDPA, TelephonyManager.NETWORK_TYPE_HSUPA, TelephonyManager.NETWORK_TYPE_HSPA, TelephonyManager.NETWORK_TYPE_EVDO_B //api<9 : replace by 14
                        , TelephonyManager.NETWORK_TYPE_EHRPD  //api<11 : replace by 12
                        , TelephonyManager.NETWORK_TYPE_HSPAP  //api<13 : replace by 15
                    -> strNetworkType = "3G"
                    TelephonyManager.NETWORK_TYPE_LTE    //api<11 : replace by 13
                    -> strNetworkType = "4G"
                    else ->
                        // http://baike.baidu.com/item/TD-SCDMA 中国移动 联通 电信 三种3G制式
                        if (_strSubTypeName.equals("TD-SCDMA", ignoreCase = true) || _strSubTypeName.equals("WCDMA", ignoreCase = true) || _strSubTypeName.equals("CDMA2000", ignoreCase = true)) {
                            strNetworkType = "3G"
                        } else {
                            strNetworkType = _strSubTypeName
                        }
                }
            }
        }
        return strNetworkType
    }


    /**
     * 获取应用详情页面intent
     *
     * @param context 上下文
     * @return
     */
    fun getAppDetailSettingIntent(context: Context): Intent {
        val localIntent = Intent()
        localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        if (Build.VERSION.SDK_INT >= 9) {
            localIntent.action = "android.settings.APPLICATION_DETAILS_SETTINGS"
            localIntent.data = Uri.fromParts("package", context.packageName, null)
        } else if (Build.VERSION.SDK_INT <= 8) {
            localIntent.action = Intent.ACTION_VIEW
            localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails")
            localIntent.putExtra("com.android.settings.ApplicationPkgName", context.packageName)
        }
        return localIntent
    }


}
